/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package platform;

import zorg.platform.RtpPacket;

/**
 *
 * @author Tomasz Nowak
 */
public class TenorSrtpPacket implements RtpPacket
{
	/*
	 * first byte
	 */
	byte version;
	Padding padding;
	Extension extension;
	byte csrcCount;

	/*
	 * second byte
	 */
	Marker marker;
	PayloadType payloadType;
	/*
	 * 3rd and 4th byte
	 */
	int sequenceNumber;
	int timestamp;
	int ssrcIndentifier;

	private int payloadLength;

	private byte[] packet;

	enum Marker
	{
		On(( byte ) 0x80),
		Off(( byte ) 0x00);
		private byte numVal;

		private Marker( byte numVal )
		{
			this.numVal = numVal;
		}

		public byte getNumVal()
		{
			return numVal;
		}
	}

	enum PayloadType
	{
		Tenor(( byte ) 0x2c),
		Tenor2(( byte ) 0x2d);
		private byte numVal;

		private PayloadType( byte numVal )
		{
			this.numVal = numVal;
		}

		public byte getNumVal()
		{
			return numVal;
		}
	}

	enum Padding
	{
		On(( byte ) 0x20),
		Off(( byte ) 0);
		private byte numVal;

		private Padding( byte numVal )
		{
			this.numVal = numVal;
		}

		public byte getNumVal()
		{
			return numVal;
		}
	};

	enum Extension
	{
		On(( byte ) 0x10),
		Off(( byte ) 0);
		private byte numVal;

		private Extension( byte numVal )
		{
			this.numVal = numVal;
		}

		public byte getNumVal()
		{
			return numVal;
		}
	};

	private void setVariables( byte[] packet )
	{
		version = ( byte ) 0x80;
		padding = Padding.values()[packet[0] & Padding.On.getNumVal()];
		extension = Extension.values()[packet[0] & Extension.On.getNumVal()];
		setCRCSCount(( byte ) (packet[0] & 0x0F));

		marker = Marker.values()[packet[1] & Marker.On.getNumVal()];
		byte b = ( byte ) (packet[1] & 0x7F);
		//payloadType = PayloadType.values()[ packet[1]];
		payloadType = PayloadType.Tenor;

		sequenceNumber = getSequenceNumber();
		timestamp = bytesToInt(packet, 4, 4);
		ssrcIndentifier = bytesToInt(packet, 4, 8);
	}

	private void setPacket()
	{
		packet[0] = getFirstByte();
		packet[1] = getSecondByte();
		byte[] tmp = get3rdAnd4thByte();
		packet[2] = tmp[0];
		packet[3] = tmp[1];

		int idx = 4;
		for ( int i = 0; i < 4; ++i, ++idx )
		{
			packet[idx] = ( byte ) ((timestamp & (0xFF << i * 8)) >> i * 8);
		}

		for ( int i = 0; i < 4; ++i, ++idx )
		{
			packet[idx] = ( byte ) ((ssrcIndentifier & (0xFF << i * 8)) >> i * 8);
		}
	}

	public TenorSrtpPacket( int sequenceNumber_, int timestamp_, int ssrc, byte[] payload_ )
	{
		packet = new byte[payload_.length + getHeaderLength() + zorg.SRTP.HMAC_AUTH_SIZE_BYTES];

		version = ( byte ) 0x80;
		padding = Padding.Off;
		extension = Extension.Off;
		setCRCSCount(( byte ) 0x00);
		marker = Marker.Off;
		payloadType = PayloadType.Tenor;
		sequenceNumber = sequenceNumber_;
		timestamp = timestamp_;
		ssrcIndentifier = ssrc;

		setPacket();

		System.arraycopy(payload_, 0, packet, getHeaderLength(), payload_.length);

		payloadLength = payload_.length;

	}

	public TenorSrtpPacket( byte[] packet_ )
	{
		packet = new byte[packet_.length];
		System.arraycopy(packet_, 0, packet, 0, packet_.length);

		payloadLength = packet_.length - getHeaderLength();
		setVariables(packet_);

	}

	private static int bytesToInt( byte[] bytes, int length, int offset )
	{
		int result = 0x0;
		for ( int i = 0; i < length; ++i )
		{
			result <<= 8;
			result |= bytes[i + offset];
		}
		return result;
	}

	@Override
	public int getSequenceNumber()
	{
		return ((( int ) packet[2] << 8) | ( int ) packet[3]);
	}

	@Override
	public byte[] getPacket()
	{
		return packet;
	}
// assert(aPacket.getPacket().length >= aPacket.getLength() + HMAC_AUTH_SIZE_BYTES);

	@Override
	public int getLength()
	{
		return getHeaderLength() + payloadLength;
	}

	@Override
	public int getPayloadLength()
	{
		return payloadLength;
	}

	@Override
	public void setPayloadLength( int length )
	{
		payloadLength = length;

	}

	@Override
	public int getHeaderLength()
	{
		return 12;
	}

	@Override
	public int getSscr()
	{
		return bytesToInt(packet, 4, 8);
	}

	public void setSequenceNumber( int value )
	{
		sequenceNumber = value;
		packet[2] = ( byte ) ((value & 0xFF00) >> 8);
		packet[3] = ( byte ) (value & 0xFF);
	}

	private byte getFirstByte()
	{
		byte result = 0x00;

		result |= version;
		result |= padding.getNumVal();
		result |= extension.getNumVal();
		result |= csrcCount;

		return result;
	}

	private byte getSecondByte()
	{
		byte result = 0x00;

		result |= marker.getNumVal();
		result |= payloadType.getNumVal();
		return result;
	}

	private byte[] get3rdAnd4thByte()
	{
		byte[] result = new byte[2];

		result[0] = ( byte ) ((sequenceNumber & 0xFF00) >> 8);
		result[1] = ( byte ) (sequenceNumber & 0xFF);

		return result;
	}

	private void resolvePadding()
	{
		padding = Padding.Off;
	}

	private void setCRCSCount( byte value )
	{
		if ( value > 0x0F || value < 0 )
		{
			throw new IllegalArgumentException("value");
		}

		csrcCount = value;
		packet[0] |= value;
	}

	private void resolveExtension()
	{
		extension = Extension.Off;
	}
}
